# -*- coding: utf-8 -*-
import os
import re
import uuid

from db.repository.qa_file import db_list_qa_attaches_by_file_id

from loguru import logger
from fastapi import FastAPI, BackgroundTasks
from starlette.responses import FileResponse, PlainTextResponse
from fastapi.middleware.cors import CORSMiddleware

from schemas.response_entity import JsonModel
from utils.file_utils import replace_img_src, download_attachment, to_abs_path


def create_app():
    app = FastAPI()
    app.add_middleware(
        CORSMiddleware,
        allow_origins=["*"],  # 允许所有来源
        allow_credentials=True,
        allow_methods=["*"],  # 允许所有方法
        allow_headers=["*"],  # 允许所有头
    )

    from middleware.permission_middleware import PermissionMiddleware
    app.add_middleware(PermissionMiddleware)

    from db import engine, init_db
    if init_db():
        logger.info(f"所有表创建/更新成功")

    from controller.chat import router as chat
    app.include_router(chat)

    from controller.users import router as user_router
    app.include_router(user_router)

    from controller.knowledge import router as knowledge
    app.include_router(knowledge)

    from controller.conversation import router as conversation
    app.include_router(conversation)

    from controller.exams import router as exam
    app.include_router(exam)

    from controller.clause import router as clause
    app.include_router(clause)

    from controller.chunks import router as chunks
    app.include_router(chunks)

    from controller.files import router as file_router
    app.include_router(file_router)

    from controller.attributes import router as attributes_router
    app.include_router(attributes_router)

    from controller.thesaurus import router as thesaurus_router
    app.include_router(thesaurus_router)

    from controller.crawler import router as crawler_router
    app.include_router(crawler_router)

    from controller.files import router as audio_router
    app.include_router(audio_router)

    @app.get("/image/{img_name}")
    async def get_img(background_task: BackgroundTasks, img_name: str):
        # 本地图片如果不存在，则重新下载图片;
        try:
            from db.repository.qa_file import db_get_qa_img_by_name
            attach = db_get_qa_img_by_name(img_name)
            if not attach:
                img_name = img_name.replace("jpeg", "jpg")
                attach = db_get_qa_img_by_name(img_name)
            if not attach:
                return JsonModel(code=404, data=None, msg="图片未找到").to_response()
            img_path = to_abs_path(attach.location)
            if os.path.exists(img_path):
                return FileResponse(img_path, media_type="image/jpeg")
            else:
                if attach.download_link:
                    background_task.add_task(download_attachment, attach.download_link, os.path.dirname(img_path))
                return JsonModel(code=404, data=None, msg=f"本地图片不存在").to_response()
        except Exception as e:
            logger.error(e)
            return JsonModel(code=500, data=None, msg="服务错误").to_response()

    @app.get("/file/{file_id}")
    async def get_md_file(token: str, file_id: uuid.UUID):
        try:
            from db.repository.qa_file import db_get_qa_file_by_id
            file = db_get_qa_file_by_id(file_id)
            if not file:
                return JsonModel(code=404, data=None, msg="文件未找到").to_response()

            attachments = db_list_qa_attaches_by_file_id(file_id)
            md_file_name = file.hash_name.rsplit('.', 1)[0] + '.md'
            md_file_path = os.path.join(os.path.dirname(to_abs_path(file.location)), md_file_name)
            if os.path.exists(md_file_path):
                with open(md_file_path, "r", encoding="utf-8") as f:
                    text = f.read()
                result = replace_img_src(text, token, nginx_prefix="/api2", attachments=attachments)
                logger.info(f"check file: {md_file_path}")
                return PlainTextResponse(result)
            else:
                return JsonModel(code=404, data=None, msg="本地markdown文件不存在").to_response()

        except Exception as e:
            logger.error(e)
            return JsonModel(code=500, data=None, msg="服务错误").to_response()

    @app.get("/pdf/{file_id}")
    async def get_pdf_file(token: str, file_id: uuid.UUID):
        try:
            from db.repository.qa_file import db_get_qa_file_by_id
            file = db_get_qa_file_by_id(file_id)
            if not file:
                return JsonModel(code=404, data=None, msg="文件未找到").to_response()
                
            pdf_file_path = to_abs_path(file.location)
            if os.path.exists(pdf_file_path):
                return FileResponse(pdf_file_path, media_type="application/pdf")
            else:
                return JsonModel(code=404, data=None, msg="本地pdf文件不存在").to_response()

        except Exception as e:
            logger.error(e)
            return JsonModel(code=500, data=None, msg="服务错误").to_response()

    @app.get("/clause/{clause_file_id}")
    async def get_clause_file(token: str, clause_file_id: uuid.UUID):
        try:
            from db.repository.clause import db_get_clause_file_by_fileId
            clause = db_get_clause_file_by_fileId(clause_file_id, clause_type=1)
            if not clause:
                return JsonModel(code=404, data=None, msg="文件未找到").to_response()

            clause_file_path = to_abs_path(clause.location)
            if os.path.exists(clause_file_path):
                return FileResponse(clause_file_path, media_type="text/plain")
            else:
                return JsonModel(code=404, data=None, msg="本地对比条款文件不存在").to_response()

        except Exception as e:
            logger.error(e)
            return JsonModel(code=500, data=None, msg="服务错误").to_response()

    @app.get("/audio/{audio_id}")
    async def get_audio_file(token: str, audio_id: uuid.UUID):
        try:
            from db.repository.audio_file import db_get_audio_by_id
            audio = db_get_audio_by_id(audio_id)
            if not audio:
                return JsonModel(code=404, data=None, msg="音频未找到").to_response()

            audio_file_path = to_abs_path(audio.location)
            if os.path.exists(audio_file_path):
                return FileResponse(audio_file_path, media_type="audio/mpeg")
            else:
                return JsonModel(code=404, data=None, msg="本地音频文件不存在").to_response()

        except Exception as e:
            logger.error(e)
            return JsonModel(code=500, data=None, msg="服务错误").to_response()

    return app


app = create_app()

# pdf处理脚本：修改为pdf处理中间文件存在则跳过的方式；保存到mysql，如果es或者哪一步保存失败，则将之前所有处理都重置
# 删除所有file数据的脚本
# 制度审核接口：接收上传的文件，保存文件与对话的关联
# chunk接口
# 保存和展示审核结果
# 图片访问接口修改为从数据库中查找返回的方式
# 制度比对结果时的附件接口
# 本地图片如果不存在，则重新下载图片
# 非gb已经处理完的json，需要重新保存图片
# 非gb的保存图片有问题
# 修改文件名es中可能没修改成功
# 模型返回的markdown表格的处理

# todo: 单文件chat不需要rerank过滤，如果能提前知道这个文件在哪个库中就更好了
# todo: es操作：修改和删除时对多库的处理
# todo: 接入ppt
# todo: 试题生成
# todo: 水印logo计算相似度后，不返回到前端（根据图片大小和分辨率判断水印）

if __name__ == "__main__":
    import uvicorn
    import argparse

    parser = argparse.ArgumentParser()
    parser.add_argument("--host", type=str, default="0.0.0.0")
    parser.add_argument("--port", type=int, default=8004)
    args = parser.parse_args()

    uvicorn.run(app, host=args.host, port=args.port)

# nohup myenv/bin/uvicorn main:app --host 0.0.0.0 --port 8001 --workers 4 > run.log 2>&1 &
# nohup myenv/bin/uvicorn portAI_app:app --host 0.0.0.0 --port 8004 --workers 2 > 8004.log 2>&1 &
# uvicorn portAI_app:app --host 0.0.0.0 --port 8004 --workers 2
# huey_consumer huey_app.huey

# gunicorn --config gunicorn_config.py portAI_app:app --daemon --pid gunicorn.pid
